//////////////////////////////////////////////
// JpgDecompressionUtils.h
//
//////////////////////////////////////////////

/// Defines / Macros -------------------------

#pragma once

/// Includes ---------------------------------

// nkImages
#include "../Data/JpgHuffmanTable.h"
#include "../Data/JpgQuantizationTable.h"
#include "../Data/JpgScan.h"

#include "../Enums/JpgComponentType.h"

#include "JpgBitStream.h"

// Standards
#include <vector>

/// Internals --------------------------------

namespace nkImages::jpg
{
	struct PreprocessedJpgScanData
	{
		std::vector<std::vector<unsigned int>> _huffmanLuts ;
		JpgBitStream _dataStream ;
		const JpgScan* _scan = nullptr ;
	} ;

	struct ProgressiveJpgReconstructionParameters
	{
		std::vector<const JpgScan*> _scans ;
		std::vector<JpgBitStream*> _streams ;
		std::vector<const PreprocessedJpgScanData*> _preprocessedData ;
		std::vector<unsigned int> _eobCounts ;
		std::vector<unsigned int> _huffmanLutIndices ;
	} ;
}

/// Class ------------------------------------

namespace nkImages::jpg
{
	class JpgDecompressionUtils
	{
		public :

			// Arithmetic
			static float clamp255 (float x) ;

			// Dct
			static void inverseDct8x8 (float* in, float* out) ;

			// Jpeg structure
			static bool isMarker (const unsigned char* ptr, unsigned char suffix) ;
			static bool isIgnoredMarker (const unsigned char* ptr) ;
			static const unsigned char* getToNextMarker (const unsigned char* data) ;
			static unsigned short getSectionSize (const unsigned char* ptr) ;

			// Huffman
			static std::vector<unsigned int> buildHuffmanLut (const JpgHuffmanTable& table) ;
			static unsigned char findNextHuffmanSymbol (JpgBitStream& dataStream, const std::vector<unsigned int>& huffmanLut, unsigned int maxLength) ;

			// Preprocessing
			static std::vector<PreprocessedJpgScanData> preprocessScanDataForProgressive (const std::vector<JpgScan>& scanData) ;
			static ProgressiveJpgReconstructionParameters reconstructionDataGatherLambda (std::vector<PreprocessedJpgScanData>& scanData, JPG_COMPONENT_TYPE targetType) ;

			// Mcu logic
			static int getDcFromCode (unsigned int code, unsigned int length) ;
			static void unpackAcRle (float* dctMcu, JpgBitStream& dataStream, const std::vector<unsigned int>& huffmanLut, unsigned int maxLength, const JpgQuantizationTable& quantizationTable) ;
			static void unpackAcRleProgressive (int* dctMcu, JpgBitStream& dataStream, const std::vector<unsigned int>& huffmanLut, unsigned int maxLength, unsigned int acStart, unsigned int acEnd, unsigned char positionLow, unsigned int& eobCount) ;
			static void decodeNextMcu (JpgBitStream& dataStream, float* dctMcu, float* currentMcu, float& lastDcValue, const std::vector<unsigned int>& huffmanLutDc, const std::vector<unsigned int>& huffmanLutAc, const JpgHuffmanTable& huffmanTableDc, const JpgHuffmanTable& huffmanTableAc, const JpgQuantizationTable& quantizationTable) ;
			static void recomposeNextProgressiveMcu (ProgressiveJpgReconstructionParameters& parameters, int& lastDcValue, float* dctMcu, float* outMcu, const JpgQuantizationTable& quantizationTable) ;
	} ;
}